#include "GameConsole.h"
#include "..\content\Shader.h"
#include "..\cvar\CVar.h"
#include "..\content\Material.h"

namespace ds {

const int LINE_HEIGHT = 20;

GameConsole::~GameConsole(void) {
	delete m_Buffer;
}

void GameConsole::init() {	

	ResourceHandle sqh = gEngine->getResourceManager().createMaterial("ConsoleMaterial");	
	Material* m = gEngine->getResourceManager().getMaterial(sqh);
	m->setAlpha(true);
	ColorShader* m_CircleShader = new ColorShader("Coloured",Color(0.1f,0.1f,0.1f,0.6f));
	m_CircleShader->init();
	ResourceHandle shaderHandle = gEngine->getResourceManager().addShader("Coloured",m_CircleShader);
	m->addShader(shaderHandle);
	m_Buffer = new TransformedTexturedBuffer(32,32,false);
	//if ( !gEngine->getResourceManager().contains("Verdana_16") ) {
		gEngine->getResourceManager().loadFont("Verdana_16","Verdana",16,true);
	//}
	IDirect3DDevice9 * pDevice = gEngine->getDevice();
	HR(D3DXCreateSprite( pDevice, &m_Sprite ));
	setMaterialName("ConsoleMaterial");
	rebuild();
}

void GameConsole::OnChar(char ascii,unsigned int keyState) {
	if ( m_Active ) {
		addChar(ascii);
	}
}

void GameConsole::OnKeyUp( WPARAM virtualKeyCode ) {
	if ( virtualKeyCode == VK_UP ) {		
		m_CurrentLine = m_Lines[m_HistoryIdx];
		--m_HistoryIdx;
		if ( m_HistoryIdx < 0 ) {
			m_HistoryIdx = 0;
		}
	}
	if ( virtualKeyCode == VK_DOWN ) {
		++m_HistoryIdx;
		if ( m_HistoryIdx >= m_Lines.size() ) {
			m_HistoryIdx = m_Lines.size()-1;
		}
		m_CurrentLine = m_Lines[m_HistoryIdx];
	}
}
void GameConsole::addChar(char ascii) {	
	// backspace pressed
	if ( ascii == 8 ) {
		// if there isn't anything in the user input return
		if ( m_CurrentLine.length() != 0) {
			m_CurrentLine.erase(m_CurrentLine.length()-1,1);		
		}
	}
	// enter pressed
	if ( ascii == 13) {
		// process line
		processLine();		
		// clear user input
		m_CurrentLine = "";
		m_HistoryIdx = m_Lines.size()-1;
	}
	if ( ascii >= 32 ) {		
		m_CurrentLine += ascii;
	}	
}

void GameConsole::processLine() {
	m_Lines.push_back(m_CurrentLine);	
	// now execute command
	
	ConsoleParameters cp(m_CurrentLine);
	if ( m_Functions.find(cp.getCommand()) != m_Functions.end()) {
		consoleFunctionPointer cfp = m_Functions[cp.getCommand()];
		std::string message = "";
		bool ret = cfp(cp,&message);
	}
	else {
		for ( size_t i = 0; i < m_Listeners.size(); ++i ) {
			m_Listeners[i]->onSubmit(cp);
		}	
	}
	while ( m_Lines.size() > m_HistorySize ) {
		LineIterator li = m_Lines.begin();
		m_Lines.erase(li);
	}
}

void GameConsole::rebuild() {		
	m_Buffer->clear();
	int ar[6] = {0,1,2,1,3,2};
	float x = m_StartPos.x;
	float y = m_StartPos.y;
	float dimX = m_Size.x;
	float dimY = m_Size.y;
	m_Buffer->add(TransformedTexturedVertex(Vec3(x,y,1.0f),Vec2(0.0f,0.0f)));
	m_Buffer->add(TransformedTexturedVertex(Vec3(x+dimX,y,1.0f),Vec2(1.0f,0.0f)));
	m_Buffer->add(TransformedTexturedVertex(Vec3(x,y+dimY,1.0f),Vec2(0.0f,1.0f)));
	m_Buffer->add(TransformedTexturedVertex(Vec3(x+dimX,y+dimY,1.0f),Vec2(1.0f,1.0f)));
	for ( int i = 0; i < 6; ++i ) {
		m_Buffer->addIndex(ar[i]);
	}
	m_Buffer->update();
}

void GameConsole::prepareRendering() {
	m_Buffer->prepareData();
}

void GameConsole::draw() {
	m_Buffer->render(2);
	IDirect3DDevice9 * pDevice = gEngine->getDevice();
	ID3DXFont *font = gEngine->getResourceManager().getFont("Verdana_16");	
	if ( font != 0 ) {
		RECT font_rect;	
		int ys = (int)m_StartPos.y + (int) m_Size.y;
		m_Sprite->Begin( D3DXSPRITE_ALPHABLEND );		
		int start = 0;
		int y = ys - m_Lines.size()*LINE_HEIGHT-LINE_HEIGHT;
		if ( m_Lines.size() > m_TotalLines ) {
			start = m_Lines.size() - m_TotalLines;
			y = ys - m_TotalLines*LINE_HEIGHT-LINE_HEIGHT;
		}				
		for ( size_t i = start; i < m_Lines.size();i++) {
			SetRect(&font_rect,0,y,200,y+LINE_HEIGHT);		
			font->DrawTextA(m_Sprite,m_Lines[i].c_str(),-1,&font_rect,DT_LEFT|DT_NOCLIP,Color(1.0f,1.0f,1.0f,1.0f));
			y += LINE_HEIGHT;
		}
		y = ys - LINE_HEIGHT;
		SetRect(&font_rect,0,y,200,y+LINE_HEIGHT);		
		font->DrawTextA(m_Sprite,">",-1,&font_rect,DT_LEFT|DT_NOCLIP,Color(1.0f,1.0f,1.0f,1.0f));				
		SetRect(&font_rect,20,y,200,y+LINE_HEIGHT);		
		font->DrawTextA(m_Sprite,m_CurrentLine.c_str(),-1,&font_rect,DT_LEFT|DT_NOCLIP,Color(1.0f,1.0f,1.0f,1.0f));				
		m_Sprite->End();
	}
}

// -------------------------------------------------------------
//
// -------------------------------------------------------------
ConsoleParameters::ConsoleParameters(std::string line) {
	commandLine = line;
	splitLine();
}


ConsoleParameters::~ConsoleParameters(void) {
}

template<class T> T ConsoleParameters::fromString(const std::string& s) {
	std::istringstream stream (s);
	T t;
	stream >> t;
	return t;
}

std::string ConsoleParameters::get(int index) {
	return items[index];
}

float ConsoleParameters::getFloat(int index) {
	return fromString<float>(get(index));
}

void ConsoleParameters::splitLine() {
	std::string word;
	std::stringstream stream(commandLine);
	int cnt = 0;
	while( getline(stream, word, ' ') ) {
		// first one is the command itself
		if ( cnt != 0 ) {
			items.push_back(word);
		}
		else {
			command = word;
		}
		cnt++;
	}
}

Vec3 ConsoleParameters::getVec3(int index) {
	float x = getFloat(index);
	float y = getFloat(index+1);
	float z = getFloat(index+2);
	return Vec3(x,y,z);
}

Vec2 ConsoleParameters::getVec2(int index) {
	float x = getFloat(index);
	float y = getFloat(index+1);
	return Vec2(x,y);
}

int ConsoleParameters::getInt(int index) {
	return fromString<int>(get(index));
}

// ---------------------------------------------------------------
// Console commands 
// ---------------------------------------------------------------
bool consoleStopUpdates(const ConsoleParameters& parameters,std::string* message) {
	gEngine->toggleUpdateAllowed();
	return true;
}

bool consoleSetCVar(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	gCV->setFromString(cp.get(0),cp.get(1));
	return true;
}

bool consoleSaveCVar(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	gCV->save(cp.get(0));
	return true;
}

bool consoleLoadCVar(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	//gCV->load(cp.get(0));
	return true;
}

bool consolePlaySound(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	gEngine->getAudioManager().play(cp.get(0).c_str(),cp.getInt(1),false);
	return true;
}

bool consoleShowLayers(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	gEngine->getWorld().debug();
	return true;
}

bool consoleReloadShader(const ConsoleParameters& parameters,std::string* message) {
	ConsoleParameters cp = parameters;
	std::string name = cp.get(0);
	ResourceHandle rh = gEngine->getResourceManager().findByName(name.c_str(),RS_SHADER);
	if ( rh.m_Type != 0 ) {
		Shader& shader = gEngine->getResourceManager().getShader(rh);
		shader.reload();
	}
	return true;
}

}

